Security News
vlt Debuts New JavaScript Package Manager and Serverless Registry at NodeConf EU
vlt introduced its new package manager and a serverless registry this week, innovating in a space where npm has stagnated.
@nextgis/expression
Advanced tools
Flexible object operations with expressions inspired by Mapbox Style
@nextgis/expression is a versatile library designed for executing actions on objects based on expressions inspired by the syntax of Mapbox Style expressions. These expressions are JSON-serializable, making them perfect for configurations, data processing, or any other kind of object manipulation.
# latest stable
$ npm install --save-dev @nextgis/expression
# or
$ yarn add @nextgis/expression
Expressions are like little command lists inside arrays. The first item in this list tells you what action to do, like "add" or "multiply". The items after that are the things you're acting on.
For example, to multiply 5 by 3:
const myExpression = ["*", 5, 3];
To find out what this equals, use the evaluate function:
import { evaluate } from '@nextgis/expression';
const answer = evaluate(["*", 5, 3]);
console.log(answer); // This will show: 15
You can even put expressions inside other expressions:
const biggerExpression = ["+", ["*", 5, 3], 4]; // This is like saying (5 times 3) plus 4
const biggerAnswer = evaluate(biggerExpression);
console.log(biggerAnswer); // This will show: 19
When we need to retrieve data stored in an object, the second argument in evaluate becomes invaluable.
Imagine you have some data:
const lakeData = {
name: "Baikal",
depth: 1642, // in meters
volume: "23,600 km³", // in cubic kilometers
islands: ["Olkhon", "Big Ushkany", "Small Ushkany"]
};
You can use expressions to access or manipulate parts of this data.
To fetch the name of the lake:
const nameExpression = ["get", "name"];
Execute this with evaluate, passing in both the expression and the data:
const lakeName = evaluate(["get", "name"], lakeData);
console.log(lakeName); // Outputs: "Baikal"
Want the first island from the "islands" array? Do this:
const islandExpression = ["at", 0, ["get", "islands"]];
const firstIsland = evaluate(islandExpression, lakeData);
console.log(firstIsland); // Outputs: "Olkhon"
To visually represent data, sometimes we might want to assign colors based on numerical values. For instance, we can use interpolation to determine a color for Lake Baikal based on its depth.
Let's decide on a simple color gradient:
Up to 500 meters: Light Blue (#ADD8E6) At 1642 meters (Baikal's maximum depth): Deep Blue (#00008B)
const colorExpression = [
"interpolate", ["linear"], ["get", "depth"],
500, "#ADD8E6", // Light Blue up to 500 meters
1642, "#00008B" // Deep Blue at Baikal's max depth
];
const derivedColor = evaluate(colorExpression, lakeData);
console.log(derivedColor); // Assuming the depth of `lakeData` is at its max, outputs: "#00008B", which corresponds to the Deep Blue color
Let's move on to exploring all possible expression types and examples of their use.
Expressions under the "Types" category are designed to work with and convert data types. Here are some of the available types expressions:
The literal expression provides a way to explicitly label a value as a raw constant, ensuring that it's interpreted as a literal instead of an expression. This can be especially useful in scenarios where there might be ambiguity.
import { evaluate } from '@nextgis/expression';
// Without 'literal', the array might be interpreted as an expression.
const literalExpression = ['literal', [10, 20, 30]];
console.log(evaluate(literalExpression)); // [10, 20, 30]
For defining arrays and specifying types within arrays.
Basic Array
import { evaluate } from '@nextgis/expression';
const obj = { array: [1,2,3] }
console.log(evaluate(['array', ['get', 'array']], obj)); // [1, 2, 3]
Typed Array
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['array', 'number', ['get', 'array']])); // [1, 2, 3] as number[]
Fixed Length Typed Array
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['array', 'string', 2, ["literal", ["Hello", "World"]]])); // ["Hello", "World"] as string[2]
These are basic type expressions to directly specify a particular type of data.
Example:
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['boolean', true])); // true
console.log(evaluate(['number', 42])); // 42
console.log(evaluate(['object', ['literal', { key: "value" }]], obj)); // { key: "value" }
console.log(evaluate(['string', "Hello World"])); // "Hello World"
If multiple values are provided for type expressions like 'boolean', each one is evaluated in order until a result of the specified type is obtained. If none of the provided values match the specified type, the expression results in an error.
// Fallback until a boolean is found
console.log(evaluate(['boolean', "not a boolean", "still not a boolean", true])); // true
// Results in an error since none of the values are booleans
try {
console.log(evaluate(['boolean', "not a boolean", "still not a boolean", 42]));
} catch (error) {
console.error(error.message); // Error: received a mismatched type
}
These expressions allow for type conversions.
const obj = {
value1: "true",
value2: "hello", // Not a number
value3: 100
};
console.log(evaluate(['to-boolean', ["get", "value1"], true], obj)); // true
console.log(evaluate(['to-number', ["get", "value2"], ["get", "value3"]], obj)); // 100 (because "hello" isn't a number, so it takes value3)
console.log(evaluate(['to-string', ["get", "value3"]], obj)); // "100"
This expression returns the type of the given value.
const obj = {
value: [1, 2, 3]
};
console.log(evaluate(['typeof', ["get", "value"]], obj)); // "array"
The Lookup category of expressions allows users to access and modify specific parts of the data. This category includes methods to extract a value by its key or index, determine if an object has a certain property, find out the length of a string or array, and many others.
Fetches a value from an array using an index.
import { evaluate } from '@nextgis/expression';
const obj = {
values: [10, 20, 30, 40]
};
console.log(evaluate(['at', 2, ['get', 'values']], obj)); // 30
Retrieves the value of a property from an object.
const obj = {
foo: 'bar',
key: 'foo',
nested: { key: 'value' },
};
// should get value from obj using key
console.log(evaluate(['get', 'foo'], obj)) // bar
console.log(evaluate(['get', 'nested'], obj)) // { key: 'value' }
// should get value from evaluated object using key
console.log(evaluate(['get', 'key', ['get', 'nested']], obj)) // 'value'
// should return null for nonexistent keys
console.log(evaluate(['get', 'nonexistent'], obj)) // null
console.log(evaluate(['has', 'width'], { type: 'River', width: 30 })); // true
console.log(evaluate(['has', 'width', ['literal', { type: 'River', width: 30 }]])); // true
Returns the length of a string or an array.
console.log(evaluate(['length', ['get', 'name']], { name: 'NextGIS' })); // 7
Checks if an element exists in an array.
console.log(evaluate(['in', 'blue', ['get', 'colors']], {
colors: ['red', 'blue', 'green']
})); // true
Returns the index of the first occurrence of a substring or an array element.
const obj = {
colors: ['red', 'blue', 'green']
};
console.log(evaluate(['index-of', 'blue', ['get', 'colors']], obj)); // 1
Returns a subsection of a string or an array.
const obj = {
animals: ['dog', 'cat', 'bird', 'fish']
};
console.log(evaluate(['slice', ['get', 'animals'], 1, 3], obj)); // ['cat', 'bird']
The Decision category provides simple tools to make comparisons and decisions based on your data. These expressions help you check equality, make logic-based choices, and more.
Returns the logical negation of the input.
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['!', true])); // false
Checks if two values are not equal.
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['!=', ['get', 'type'], 'River'], { type: 'Stream' })); // true
Checks if the first value is less than the second.
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['<', ['get', 'length'], 100], { length: 80 })); // true
Checks if the first value is less than or equal to the second.
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['<=', ['get', 'length'], 100], { length: 100 })); // true
Checks if two values are equal.
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['==', ['get', 'type'], 'River'], { type: 'River' })); // true
Checks if the first value is greater than or equal to the second.
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['>=', ['get', 'width'], 50], { width: 60 })); // true
Checks if the first value is greater than the second.
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['>', ['get', 'width'], 50], { width: 40 })); // false
Evaluates multiple conditions and returns true if all of them are true.
import { evaluate } from '@nextgis/expression';
console.log(evaluate(['all', ['>', ['get', 'width'], 50], ['==', ['get', 'type'], 'River']], { width: 60, type: 'River' })); // true
Evaluates multiple conditions and returns true if at least one of them is true.
import { evaluate } from '@nextgis/expression';
console.log(evaluate([
'any',
['>', ['get', 'width'], 100],
['==', ['get', 'type'], 'Stream']
], { width: 80, type: 'Stream' })); // true
Evaluates each pair of conditions and values sequentially and returns the output of the first true condition. If none are true, it returns the value of the optional default case.
import { evaluate } from '@nextgis/expression';
const obj = {
two: 2,
str: 'Foo Bar',
};
evaluate([
'case',
['==', ['get', 'two'], 2],
'matches two',
['==', ['get', 'str'], 'Not Foo Bar'],
'matches string',
'fallback',
],
obj,
) // 'matches two'
Matches an input with a series of cases, returning the output associated with the first matching case. If there's no match, a default value is returned.
import { evaluate } from '@nextgis/expression';
const obj = { shape: 'circle' };
console.log(evaluate([
'match',
['get', 'shape'],
'square', 'It is a square',
'circle', 'It is a circle',
'Unknown shape'],
obj)); // 'It is a circle'
Interpolation expressions allow you to create smooth transitions between values based on your input data. They can be especially useful when visualizing data gradients or when you want to transition between two values.
The step expression creates a stepped, piecewise-constant function. It's mainly used when you want to categorize your data into specific bins.
import { evaluate } from '@nextgis/expression';
const prop = { five: 5, one: 1 };
console.log(evaluate(['step', ['get', 'five'], 0, 4, 'low', 6, 'medium', 8, 'high'], prop)); // 'low'
console.log(evaluate(['step', 6, 0, 4, 'low', 6, 'medium', 8, 'high'], prop)); // 'medium'
console.log(evaluate(['step', 9, 0, 4, 'low', 6, 'medium', 8, 'high'], prop)); // 'high'
console.log(evaluate(['step', ['get', 'one'], 'low', 6, 'medium', 8, 'high'], prop)); // 'low'
The interpolate expression provides smooth transitions between pairs of input and output values.
Currently, only linear interpolation is supported.
import { evaluate } from '@nextgis/expression';
const prop = { value: 5 };
// Interpolating numbers:
console.log(evaluate([
'interpolate',
['linear'],
['get', 'value'],
0, 10,
10, 20
], prop)); // 15
// Interpolating HEX colors:
console.log(evaluate([
'interpolate',
['linear'],
['get', 'value'],
0, '#000000',
10, '#ffffff'
], prop
)); // 'rgb(128,128,128)'
// Interpolating Named colors:
console.log(evaluate([
'interpolate',
['linear'],
['get', 'value'],
0, 'black',
10, 'white'
], prop
)); // 'rgb(128,128,128)'
// Interpolating RGB colors:
console.log(evaluate([
'interpolate',
['linear'],
['get', 'value'],
0, 'rgb(0,0,0)',
10, 'rgb(255,255,255)'
], prop)); // 'rgb(128,128,128)'
// Interpolating with multiple stops
console.log(evaluate([
'interpolate',
['linear'],
14,
0, 10,
5, 20,
10, 30,
15, 40
])); // 38
The Math category includes a comprehensive set of mathematical operations to perform arithmetic, trigonometric, logarithmic, and other related calculations.
Supported Operations:
import { evaluate } from '@nextgis/expression';
// Summation (multiple arguments):
evaluate(['+', 1, 2, 3, 4]); // Outputs: 10
// Subtraction (two arguments):
evaluate(['+', 1, 2, 3, 4]); // Outputs: 10
// Sine function (single argument):
evaluate(['sin', ['/', 'pi', 2]]); // Outputs: 1
Need to fix a bug or add a feature to @nextgis/expression
? We provide custom development and support for this software. Contact us to discuss options!
FAQs
Flexible object operations with expressions inspired by Mapbox Style
The npm package @nextgis/expression receives a total of 25 weekly downloads. As such, @nextgis/expression popularity was classified as not popular.
We found that @nextgis/expression demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
vlt introduced its new package manager and a serverless registry this week, innovating in a space where npm has stagnated.
Security News
Research
The Socket Research Team uncovered a malicious Python package typosquatting the popular 'fabric' SSH library, silently exfiltrating AWS credentials from unsuspecting developers.
Security News
At its inaugural meeting, the JSR Working Group outlined plans for an open governance model and a roadmap to enhance JavaScript package management.